#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@Author          : ricsy
@File            : base_interactive.py
@Create Time     : 2025/6/18 03:22
@Last Modified   :
@Description     : 交互式配置生成器抽象基类
"""
from abc import ABC, abstractmethod
from datetime import datetime

import ipywidgets as widgets
from IPython.core.display import HTML
from IPython.display import display
from myst_nb import glue


class BaseInteractive(ABC):
    # 必须由子类覆盖的常量
    DIRECTIVE_NAME = None
    CLASS_PREFIX = None
    BACKTICKS = "```"

    # 必须由子类覆盖的配置
    DEFAULT_OPTIONS = {}
    CONTROL_LAYOUT_CONFIG = {}

    def __init__(self):
        self.controls = {}
        self.current_params = {}
        self.generate_btn = None
        self.reset_btn = None
        self.config_output = widgets.Output()

        # 嵌入变量
        self.preview_timestamp = ""
        self.preview_code = ""
        self.glue_timestamp_key = f"{self.CLASS_PREFIX}-timestamp"
        self.glue_code_key = f"{self.CLASS_PREFIX}-code"

    @abstractmethod
    def build_main_layout(self):
        """子类必须实现的布局构建方法"""

    def before_run(self):
        """
        执行前的预处理钩子
        """

    @staticmethod
    def custom_control_init(_control_name, widget):
        """
        自定义控件初始化
        :param _control_name: 控件名称
        :param widget: 控件实例
        :return: 处理后的控件实例
        """
        return widget

    def initialize_components(self):
        """初始化所有组件"""
        from extensions.common import init_buttons, init_controls

        # 预处理钩子
        self.before_run()

        # 初始化控件
        self.controls = init_controls(self.DEFAULT_OPTIONS, self.CLASS_PREFIX)

        # 初始化按钮
        self.generate_btn, self.reset_btn = init_buttons(
            self.on_generate_click, self.on_reset_click
        )

        # 设置控件布局
        self.set_controls_layout()

        # 构建界面布局
        return self.build_main_layout()

    def set_controls_layout(self):
        """应用控件布局配置"""
        for control_name, layout_config in self.CONTROL_LAYOUT_CONFIG.items():
            if control_name in self.controls:
                self.controls[control_name].widget.layout = widgets.Layout(
                    **layout_config
                )

    def on_param_change(self, change):
        """参数变更回调"""
        param_name = change["owner"].param_name
        self.current_params[param_name] = change["new"]

    def generate_config_output(self):
        """生成配置输出"""
        with self.config_output:
            self.config_output.clear_output()

            config_lines = [
                f"<span class='sd'>:{k}: {v}\n</span>"
                for k, v in self.current_params.items()
            ]
            config_lines_str = "".join(config_lines)

            if config_lines:
                self.preview_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                # 指令（这里拼接特定 HTML 结构，使复制按钮插件可以识别注入）
                self.preview_code = f"""
                    <div class="highlight-markdown notranslate" style="white-space: pre-wrap; font-family: monospace;">
                        <div class="highlight">
                            <pre tabindex="-1">
                                <span class='sd'>\n{self.BACKTICKS}{{{self.DIRECTIVE_NAME}}}\n</span>{config_lines_str}<span class='sd'>{self.BACKTICKS}</span>
                            </pre>
                        </div>
                    </div>
                """
            else:
                print("请先修改参数再生成配置")

    def on_generate_click(self, _b):
        """生成配置按钮回调"""
        self.current_params.update({k: v.value for k, v in self.controls.items()})
        self.generate_config_output()

    def on_reset_click(self, _b):
        """重置按钮回调"""
        for control in self.controls.values():
            control.reset()
        self.current_params.clear()
        with self.config_output:
            self.config_output.clear_output()

    def add_glue_vars(self):
        """添加嵌入变量"""
        glue(
            self.glue_timestamp_key,
            self.preview_timestamp,
            display=False,
        )
        glue(
            self.glue_code_key,
            HTML(self.preview_code),
            display=False,
        )

    def run(self):
        """主运行流程"""
        # 初始化组件
        main_layout = self.initialize_components()
        # 添加 JS 容器标识
        main_layout.add_class(f"widget-{self.CLASS_PREFIX}-area")

        # 注册事件监听
        for control in self.controls.values():
            control.observe(self.on_param_change)

        # 显示界面
        display(main_layout)

        # 生成嵌入变量
        self.add_glue_vars()
